package org.ws.httphelper.support.pipeline;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.ws.httphelper.core.pipeline.HttpHandler;
import org.ws.httphelper.core.pipeline.HttpPipeline;
import org.ws.httphelper.core.pipeline.RequestHandler;
import org.ws.httphelper.core.pipeline.RequestInvoke;
import org.ws.httphelper.core.pipeline.ResponseHandler;
import org.ws.httphelper.core.pipeline.ResponseInvoke;
import org.ws.httphelper.exception.RequestException;
import org.ws.httphelper.exception.ResponseException;
import org.ws.httphelper.model.RequestContext;

import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;

/**
 * 默认的HttpPipeline实现。
 * 由所有的handler对应的context的有序双向链表组成，顺序根据context.order从head（小）到tail（大）。
 * 每一个类型的handler只允许出现一次。
 * 执行request为从head开始向tail执行所有的RequestHandler的处理器。
 * 执行response为从tail开始向head执行所有的ResponseHandler的处理器。
 * 处理器是可以根据@HandlerOrder生成context的order进行排序，在添加时可以指定handler所在链表的位置，以保证按照优先顺序执行。
 * 允许添加可以异步执行的Handler，但是只允许ResponseHandler异步执行，因为RequestHandler需要保证全部执行后再执行请求，所以无法异步执行。
 */
public class DefaultHttpPipeline implements HttpPipeline, RequestInvoke, ResponseInvoke {

    private static Logger log = LoggerFactory.getLogger(DefaultHttpPipeline.class.getName());

    /**
     * context链表头节点
     */
    private AbstractHandlerContext head;
    /**
     * context链表尾节点
     */
    private AbstractHandlerContext tail;
    /**
     * 已存在的handler类型：用于验证是否存在相同类型的handler
     */
    private Set<Class<? extends HttpHandler>> httpHandlerClassSet;

    public DefaultHttpPipeline() {
        this.head = new HeadContext(this);
        this.tail = new TailContext(this);
        this.head.next = tail;
        this.tail.prev = head;
        this.httpHandlerClassSet = Sets.newHashSet();
    }

    /**
     * 从一个parent复制所有的handler
     * @param parent
     */
    public void copyOf(DefaultHttpPipeline parent){
        if(parent == null){
            return;
        }
        AbstractHandlerContext next = parent.head;
        List<HttpHandler> list = Lists.newArrayList();
        while (next != null){
            next = next.next;
            if(next == parent.tail){
                break;
            }
            HttpHandler handler = next.handler();
            if(!this.httpHandlerClassSet.contains(handler.getClass())){
                list.add(handler);
            }
        }
        if(CollectionUtils.isNotEmpty(list)){
            HttpHandler[] array = new HttpHandler[list.size()];
            list.toArray(array);
            addLast(array);
        }
    }

    /**
     * 将handler从head添加，若order一致，则添加到前面
     * @param handler 一个handler
     * @return
     */
    @Override
    public HttpPipeline addFirst(HttpHandler handler) {
        addFirst(null,handler);
        return this;
    }

    /**
     * 将handler从head从前向后遍历添加位置，若order一致，则添加到前面
     * @param handlers handler数组
     * @return
     */
    @Override
    public HttpPipeline addFirst(HttpHandler... handlers) {
        for (HttpHandler handler : handlers) {
            addFirst(handler);
        }
        return this;
    }

    /**
     * 添加异步执行的handler，只有responseHandler允许异步执行
     * @param executor
     * @param handler
     * @return
     */
    @Override
    public HttpPipeline addFirst(ExecutorService executor, HttpHandler handler) {
        AbstractHandlerContext context = newContext(executor, handler);
        addFirst0(context);
        return this;
    }

    /**
     * 添加异步执行的handlers，只有responseHandler允许异步执行
     * @param executor
     * @param handlers
     * @return
     */
    @Override
    public HttpPipeline addFirst(ExecutorService executor, HttpHandler... handlers) {
        for (HttpHandler handler : handlers) {
            addFirst(executor,handler);
        }
        return this;
    }

    /**
     * 生成一个新的context
     * @param executor
     * @param handler
     * @return
     */
    private AbstractHandlerContext newContext(ExecutorService executor, HttpHandler handler){
        return new DefaultHandlerContext(this,executor,handler);
    }

    /**
     * 将context从头部添加的实际处理方法
     * @param newCtx
     */
    private void addFirst0(AbstractHandlerContext newCtx){
        // 验证handler
        HttpHandler handler = newCtx.handler();
        if(!validateHandler(handler)){
            return;
        }
        // 将handle类型添加到已存在set
        httpHandlerClassSet.add(handler.getClass());
        // 从头部开始遍历
        AbstractHandlerContext nextCtx = head.next;
        // 根据order获取到追加位置，从小到大
        while (nextCtx.getOrder()<newCtx.getOrder()){
            nextCtx = nextCtx.next;
            if(nextCtx == null){
                break;
            }
        }
        // 只有tail的next为null，若为null添加位置为tail前
        if(nextCtx == null){
            nextCtx = tail;
        }
        // 将context添加到next的前面
        newCtx.prev = nextCtx.prev;
        newCtx.next = nextCtx;
        nextCtx.prev.next = newCtx;
        nextCtx.prev = newCtx;
    }

    /**
     * 将handler从tail开始从后向前遍历添加位置，若order一致，则添加到后面
     * @param handler
     * @return
     */
    @Override
    public HttpPipeline addLast(HttpHandler handler) {
        addLast(null,handler);
        return this;
    }

    /**
     * 将handler从tail开始从后向前遍历添加位置，若order一致，则添加到后面
     * @param handlers
     * @return
     */
    @Override
    public HttpPipeline addLast(HttpHandler... handlers) {
        for (HttpHandler handler : handlers) {
            addLast(handler);
        }
        return this;
    }

    /**
     * 添加异步执行的handlers，只有responseHandler允许异步执行
     * @param executor
     * @param handler
     * @return
     */
    @Override
    public HttpPipeline addLast(ExecutorService executor, HttpHandler handler) {
        AbstractHandlerContext context = newContext(executor, handler);
        addLast0(context);
        return this;
    }

    /**
     * 添加异步执行的handlers，只有responseHandler允许异步执行
     * @param executor
     * @param handlers
     * @return
     */
    @Override
    public HttpPipeline addLast(ExecutorService executor, HttpHandler... handlers) {
        for (HttpHandler handler : handlers) {
            addLast(executor,handler);
        }
        return this;
    }

    /**
     * 将context从尾部添加的实际处理方法
     * @param newCtx
     */
    private void addLast0(AbstractHandlerContext newCtx) {
        HttpHandler handler = newCtx.handler();
        // 验证是否已存在handler
        if(!validateHandler(handler)){
            return;
        }
        // 将handle类型添加到已存在set
        httpHandlerClassSet.add(handler.getClass());
        // 从尾部开始遍历
        AbstractHandlerContext prev = tail.prev;
        // 根据order查找到添加位置，从大到小
        while (prev.getOrder()>newCtx.getOrder()){
            prev = prev.prev;
            if(prev == null){
                break;
            }
        }
        // head的prev为空，若prev为空，则添加到head后面
        if(prev == null){
            prev = head;
        }
        // 添加到指定位置的后面
        newCtx.prev = prev;
        newCtx.next = prev.next;
        prev.next.prev = newCtx;
        prev.next = newCtx;
    }

    /**
     * 从header向下查询,移除类型一致handler
     * @param handlerType
     * @return
     */
    @Override
    public HttpPipeline remove(Class<? extends HttpHandler> handlerType) {
        AbstractHandlerContext removeCtx = head.next;
        // 根据handler类型找到要删除的handler
        while (!handlerType.equals(removeCtx.handler().getClass())){
            removeCtx = removeCtx.next;
            if(removeCtx == null){
                break;
            }
        }
        // 若找到，则移除
        if(removeCtx != null && removeCtx != tail){
            AbstractHandlerContext prev = removeCtx.prev;
            prev.next = removeCtx.next;
            removeCtx.next.prev = prev;
            removeCtx.next = null;
            removeCtx.prev = null;
            removeCtx = null;
        }
        return this;
    }

    /**
     * 执行request处理
     * 从head向后依次执行RequestHandler，执行同步
     * @param requestContext
     */
    @Override
    public void request(RequestContext requestContext) {
        AbstractHandlerContext.invokeRequest(requestContext,head);
    }

    /**
     * 执行response处理
     * 从tail向前依次执行ResponseHandler，若handler存在executor则异步执行
     * @param requestContext
     */
    @Override
    public void response(RequestContext requestContext) {
        AbstractHandlerContext.invokeResponse(tail,requestContext);
    }

    /**
     * 验证handler
     * @param handler
     * @return
     */
    private boolean validateHandler(HttpHandler handler){
        if(handler == null){
            return false;
        }
        else if(httpHandlerClassSet.contains(handler.getClass())){
            log.warn("HttpHandler {} has exists. Can not add.",handler.getClass());
            return false;
        }
        return true;
    }

    /**
     * 链表HeadContext，order最小为0
     */
    static final class HeadContext extends AbstractHandlerContext implements RequestHandler {

        public HeadContext(DefaultHttpPipeline pipeline) {
            super(pipeline, null);
        }

        @Override
        public HttpHandler handler() {
            return this;
        }

        @Override
        public boolean handler(RequestContext requestContext) throws RequestException {
            if(log.isDebugEnabled()) {
                log.debug("call head handler.");
            }
            return true;
        }

        @Override
        public int getOrder() {
            return 0;
        }

    }

    /**
     * 链表TailContext，order最大为Integer.MAX_VALUE
     */
    static final class TailContext extends AbstractHandlerContext implements ResponseHandler {

        public TailContext(DefaultHttpPipeline pipeline) {
            super(pipeline, null);
        }

        @Override
        public HttpHandler handler() {
            return this;
        }

        @Override
        public boolean handler(RequestContext requestContext) throws ResponseException {
            if(log.isDebugEnabled()) {
                log.debug("call tail handler.");
            }
            return true;
        }

        @Override
        public int getOrder() {
            return Integer.MAX_VALUE;
        }

    }
}
